home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amicdfilesystem / src / iso9660.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  20KB  |  836 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * Modified by Nicola Salmoria.
  6.  *
  7.  * ----------------------------------------------------------------------
  8.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  9.  * All rights reserved.
  10.  * This software may be freely distributed and redistributed for
  11.  * non-commercial purposes, provided this notice is included.
  12.  * ----------------------------------------------------------------------
  13.  * [History removed]
  14.  */
  15.  
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include <exec/types.h>
  21. #include <exec/memory.h>
  22. #include <dos/dos.h>
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/utility.h>
  26.  
  27. #include "cdrom.h"
  28. #include "iso9660.h"
  29. #include "rock.h"
  30.  
  31.  
  32. t_bool Iso_Is_Top_Level_Object (VOLUME *,CDROM_OBJ *);
  33. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume);
  34. LONG Iso_Examine_Next (VOLUME *p_volume,CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  35.               unsigned long *p_offset);
  36. void Iso_Close_Obj (CDROM_OBJ *p_object);
  37.  
  38.  
  39. #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
  40. #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
  41.  
  42. /* Check whether the given volume uses the ISO 9660 Protocol.
  43.  * The protocol is identified by the sequence
  44.  *            'C' 'D' '0' '0' '1'
  45.  * in the 2nd..6th byte of sector 16 of a track.
  46.  *
  47.  * All data tracks on the disk are examined.
  48.  *
  49.  * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
  50.  */
  51.  
  52. t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
  53. {
  54.   int i, len;
  55.   t_ulong *buf;
  56.  
  57.  
  58.   SetIoErr(ERROR_NOT_A_DOS_DISK);    /* initialize error code (Read_Sector() */
  59.                                     /* will change it if needed) */
  60.  
  61.   /* If Data_Tracks() returns -1, then the drive probably doesn't support
  62.    * the SCSI-2 READ TOC command.
  63.    */
  64.   if (p_cdrom->use_trackdisk ||
  65.       (len = Data_Tracks (p_cdrom, &buf)) < 0) {
  66.     *p_offset = 0;
  67.     if (!Read_Sector (p_cdrom, 16))
  68.       return FALSE;
  69.     return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
  70.   }
  71.  
  72.   if (len == 0)
  73.     return FALSE;
  74.  
  75.   /* Use a vendor-specific command to find the offset of the last
  76.    * session:
  77.    */
  78.   if (Find_Last_Session (p_cdrom, p_offset) &&
  79.       Read_Sector (p_cdrom, 16 + *p_offset) &&
  80.       strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  81.     FreeVec (buf);
  82.     return TRUE;
  83.   }
  84.  
  85.   /* Search all data tracks for valid primary volume descriptors: */
  86.   for (i=len-1; i>=0; i--) {
  87.     *p_offset = buf[i];
  88.     if (!Read_Sector (p_cdrom, 16 + *p_offset))
  89.       continue;
  90.     if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  91.       FreeVec (buf);
  92.       return TRUE;
  93.     }
  94.   }
  95.  
  96.   FreeVec (buf);
  97.  
  98.   /* On some disks, the information in the TOC may not be valid. Therefore
  99.    * also check sector 16:
  100.    */
  101.   if (!Read_Sector (p_cdrom, 16))
  102.     return FALSE;
  103.   if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  104.     *p_offset = 0;
  105.     return TRUE;
  106.   }
  107.  
  108.   return FALSE;
  109. }
  110.  
  111. /* Check whether the given volume uses the High Sierra Protocol.
  112.  * The protocol is identified by the sequence
  113.  *            'C' 'D' 'R' 'O' 'M'
  114.  * in the 10th..14th byte of sector 16.
  115.  *
  116.  * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
  117.  */
  118.  
  119. t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
  120. {
  121.   SetIoErr(ERROR_NOT_A_DOS_DISK);    /* initialize error code (Read_Sector() */
  122.                                     /* will change it if needed) */
  123.  
  124.   if (!Read_Sector (p_cdrom, 16))
  125.     return FALSE;
  126.  
  127.   return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
  128. }
  129.  
  130.  
  131.  
  132. t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset,
  133.         t_bool lowercase)
  134. {
  135.   long loc = 16 + p_offset;
  136.   extern t_handler g_iso_handler;
  137.  
  138.   p_volume->handler = &g_iso_handler;
  139.  
  140.   p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC | MEMF_CLEAR);
  141.   if (!p_volume->vol_info) {
  142.     SetIoErr(ERROR_NO_FREE_STORE);
  143.     return FALSE;
  144.   }
  145.  
  146.   for (;;) {
  147.     if (!Read_Sector (p_volume->cd, loc)) {
  148.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  149.       return FALSE;
  150.     }
  151.  
  152.     if (p_volume->cd->buffer[0] == 1) {
  153.       memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
  154.       break;
  155.     }
  156.  
  157.     if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
  158.       SetIoErr(ISOERR_NO_PVD);
  159.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  160.       return FALSE;
  161.     }
  162.  
  163.     loc++;
  164.   }
  165.  
  166.   VOL(p_volume,skip) = p_skip;
  167.  
  168.   switch (VOL(p_volume,pvd).block_size_m) {
  169.   case 512:
  170.     VOL(p_volume,blockshift) = 2;
  171.     break;
  172.   case 1024:
  173.     VOL(p_volume,blockshift) = 1;
  174.     break;
  175.   case 2048:
  176.   default:
  177.     VOL(p_volume,blockshift) = 0;
  178.     break;
  179.   }
  180.  
  181.   if (lowercase)
  182.   {
  183.     /* Look at the system ID to find out if the CD is supposed
  184.      * to feature proper file names. These are CDs made for use
  185.      * with the CDTV and the CD│▓ (both share the "CDTV" system ID)
  186.      * and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
  187.      * created by Mkisofs. If any of these IDs is found the
  188.      * file name to lower case conversion is disabled.
  189.      */
  190.  
  191.     if (!strncmp(VOL(p_volume,pvd).system_id,"CDTV",4) ||
  192.         !strncmp(VOL(p_volume,pvd).system_id,"AMIGA",5))
  193.     {
  194.         lowercase = 0;
  195.     }
  196.   }
  197.  
  198.   VOL(p_volume,lowercase) = lowercase;
  199.  
  200.   return TRUE;
  201. }
  202.  
  203. void Iso_Close_Vol_Info (VOLUME *p_volume)
  204. {
  205.   FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  206. }
  207.  
  208. CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
  209. {
  210. CDROM_OBJ *obj;
  211.  
  212.  
  213. if (obj = AllocMem(sizeof(CDROM_OBJ),MEMF_PUBLIC | MEMF_CLEAR))
  214. {
  215.     if (obj->obj_info = AllocMem(sizeof (t_iso_obj_info),MEMF_PUBLIC))
  216.     {
  217.         if (OBJ(obj,dir) = AllocMem(p_length_of_dir_record,MEMF_PUBLIC))
  218.             return(obj);
  219.  
  220.         FreeMem(obj->obj_info, sizeof (t_iso_obj_info));
  221.     }
  222.  
  223.     FreeMem(obj,sizeof(CDROM_OBJ));
  224. }
  225.  
  226. SetIoErr(ERROR_NO_FREE_STORE);
  227. return(NULL);
  228. }
  229.  
  230. /* Get the "CDROM object" for the root directory of the volume.
  231.  */
  232.  
  233. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
  234. {
  235.   CDROM_OBJ *obj;
  236.  
  237.   obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
  238.   if (!obj)
  239.     return NULL;
  240.  
  241.   obj->directory_f = TRUE;
  242.   obj->handler = p_volume->handler;
  243.   obj->pos = 0;
  244.   memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
  245.  
  246.   return obj;
  247. }
  248.  
  249.  
  250. /* Compare the name of the directory entry p_iso_name
  251.  * with the C string p_name, and return 1 iff strings are equal.
  252.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  253.  *       name (without version number).
  254.  * NOTE: may *TRASH* p_iso_name
  255.  */
  256.  
  257. int Names_Equal (char *p_iso_name, char *p_name)
  258. {
  259.   int pos;
  260.  
  261.  
  262.   if (!Stricmp(p_iso_name, p_name))
  263.     return TRUE;
  264.  
  265.   /* compare without version number: */
  266.  
  267.   for (pos=strlen(p_iso_name)-1; pos>=0; pos--)
  268.     if (p_iso_name[pos] == ';')
  269.       break;
  270.  
  271.   if (pos>=0)
  272.   {
  273.     p_iso_name[pos] = 0;
  274.     return(!Stricmp(p_iso_name,p_name));
  275.   }
  276.   else
  277.     return FALSE;
  278. }
  279.  
  280. /* Get a record from a directory.
  281.  * p_location is a LOGICAL BLOCK number.
  282.  * the record will be stored in buffer, which must be 256 bytes long.
  283.  */
  284.  
  285. directory_record *Get_Directory_Record (VOLUME *p_volume,struct directory_record *p_dir,
  286.                     unsigned long p_location,
  287.                     unsigned long p_offset)
  288. {
  289.   int len;
  290.   int loc;
  291.  
  292.   loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
  293.   if (!Read_Sector (p_volume->cd, loc)) {
  294.     return NULL;
  295.   }
  296.  
  297.   len = p_volume->cd->buffer[p_offset & 2047];
  298.   if (len)
  299.     memcpy (p_dir, p_volume->cd->buffer + (p_offset & 2047), len);
  300.   else
  301.     p_dir->length = 0;  /* mark as last record */
  302.  
  303.   return(p_dir);
  304. }
  305.  
  306.  
  307.  
  308. /* store the name of an object into buffer, which must be 32 bytes long */
  309. VOID Convert_Iso_Name(VOLUME *p_volume,struct directory_record *p_dir,UBYTE *buffer)
  310. {
  311. int len;
  312.  
  313.  
  314. len = -1;
  315. if (p_volume->protocol == PRO_ROCK)
  316.     len = Get_RR_File_Name(p_volume,p_dir,buffer,30);
  317.  
  318. if (len < 0)
  319. {
  320.     len = p_dir->file_id_length;
  321. /* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
  322.     if (len > 30) len = 30;
  323.  
  324.     memcpy(buffer,p_dir->file_id,len);
  325.     if (VOL(p_volume,lowercase))
  326.     {
  327. /* convert file name to lowercase if the user requested it */
  328.         WORD i;
  329.  
  330.  
  331.         for (i = 0;i < len;i++)
  332.             buffer[i] = ToLower(buffer[i]);
  333.     }
  334. }
  335.  
  336. /* NULL terminate the string */
  337. buffer[len] = 0;
  338. }
  339.  
  340.  
  341.  
  342. /* Create a "CDROM object" for the directory which is located
  343.  * at sector p_location.
  344.  */
  345.  
  346. CDROM_OBJ *Iso_Create_Directory_Obj (VOLUME *p_volume, unsigned long p_location)
  347. {
  348.   unsigned char buffer[256];
  349.   directory_record *dir = (directory_record *)buffer;
  350.   unsigned long loc;
  351.   int offset = 0;
  352.   CDROM_OBJ *obj;
  353.   unsigned long len;
  354.  
  355.   if (p_location == VOL(p_volume,pvd).root.extent_loc_m)
  356.     return Iso_Open_Top_Level_Directory (p_volume);
  357.  
  358.   if (!Get_Directory_Record (p_volume, dir, p_location, 0))
  359.     return NULL;
  360.  
  361.   if (!Get_Directory_Record (p_volume, dir, p_location, dir->length))
  362.     return NULL;
  363.  
  364.   loc = dir->extent_loc_m;
  365.   len = dir->data_length_m;
  366.   for (;;) {
  367.     if (offset >= len)
  368.       return NULL;
  369.     if (!Get_Directory_Record (p_volume, dir, loc, offset))
  370.       return NULL;
  371.     if (!dir->length) {
  372.       /* go to next logical sector: */
  373.       offset = (offset & 0xfffff800) + 2048;
  374.       continue;
  375.     }
  376.     if (dir->extent_loc_m == p_location)
  377.       break;
  378.     offset += dir->length;
  379.   }
  380.  
  381.   obj = Iso_Alloc_Obj (dir->length);
  382.   if (!obj)
  383.     return NULL;
  384.  
  385.   obj->directory_f = TRUE;
  386.   obj->handler = p_volume->handler;
  387.   obj->pos = 0;
  388.   memcpy (OBJ(obj,dir), dir, dir->length);
  389.  
  390.   return obj;
  391. }
  392.  
  393.  
  394. /* Open the object with name p_name in the directory p_dir.
  395.  * p_name must not contain '/' or ':' characters.
  396.  */
  397.  
  398. CDROM_OBJ *Iso_Open_Obj_In_Directory (VOLUME *p_volume,CDROM_OBJ *p_dir, char *p_name)
  399. {
  400.   unsigned long loc = OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length;
  401.   unsigned long len = OBJ(p_dir,dir)->data_length_m;
  402.   unsigned char buffer[256];
  403.   UBYTE namebuff[32];
  404.   directory_record *dir = (directory_record *)buffer;
  405.   int offset;
  406.   CDROM_OBJ *obj;
  407.   long cl;
  408.  
  409.   /* skip first two entries: */
  410.  
  411.   if (!Get_Directory_Record (p_volume, dir, loc, 0))
  412.     return NULL;
  413.  
  414.   offset = dir->length;
  415.   if (!Get_Directory_Record (p_volume, dir, loc, offset))
  416.     return NULL;
  417.  
  418.   offset += dir->length;
  419.   for (;;) {
  420.     if (offset >= len) {
  421.       SetIoErr(ISOERR_NOT_FOUND);
  422.       return NULL;
  423.     }
  424.     if (!Get_Directory_Record (p_volume, dir, loc, offset))
  425.       return NULL;
  426.     if (!dir->length) {
  427.       /* go to next logical sector: */
  428.       offset = (offset & 0xfffff800) + 2048;
  429.       continue;
  430.     }
  431.  
  432.     Convert_Iso_Name(p_volume,dir,namebuff);
  433.     if (Names_Equal (namebuff,p_name))
  434.       break;
  435.     offset += dir->length;
  436.   }
  437.  
  438.   if (p_volume->protocol == PRO_ROCK &&
  439.       (cl = RR_Child_Link (p_volume, dir)) >= 0)
  440.     return Iso_Create_Directory_Obj (p_volume, cl);
  441.  
  442.   obj = Iso_Alloc_Obj (dir->length);
  443.   if (!obj)
  444.     return NULL;
  445.  
  446.   obj->directory_f = (dir->flags & 2);
  447.   if (p_volume->protocol == PRO_ROCK &&
  448.       Is_A_Symbolic_Link (p_volume, dir)) {
  449.     obj->symlink_f = 1;
  450.     obj->directory_f = 0;
  451.   }
  452.   memcpy (OBJ(obj,dir), dir, dir->length);
  453.   obj->handler = p_volume->handler;
  454.   obj->pos = 0;
  455.   if (!obj->directory_f)
  456.     OBJ(obj,parent_loc) = loc;
  457.  
  458.   return obj;
  459. }
  460.  
  461. /* Close a "CDROM object" and deallocate all associated resources.
  462.  */
  463.  
  464. void Iso_Close_Obj (CDROM_OBJ *p_object)
  465. {
  466.   FreeMem (OBJ(p_object,dir), OBJ(p_object,dir)->length);
  467.   FreeMem (p_object->obj_info, sizeof (t_iso_obj_info));
  468.   FreeMem (p_object, sizeof (CDROM_OBJ));
  469. }
  470.  
  471. /* Read bytes from a file.
  472.  */
  473.  
  474. int Iso_Read_From_File (VOLUME *p_volume,CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  475. {
  476.   unsigned long loc;
  477.   int remain_block, remain_file, remain;
  478.   int len;
  479.   CDROM *cd = p_volume->cd;
  480.   int buf_pos = 0;
  481.   int todo;
  482.   unsigned long last_loc, ext_loc;
  483.   short blockshift;
  484.   int offset;
  485.   unsigned long firstblock;
  486.  
  487.  
  488.   if (p_file->pos == OBJ(p_file,dir)->data_length_m)
  489.     /* at end of file: */
  490.     return 0;
  491.  
  492.   blockshift = VOL(p_volume,blockshift);
  493.   /* 'firstblock' is the first logical block of the file section: */
  494.   firstblock = OBJ(p_file,dir)->extent_loc_m + OBJ(p_file,dir)->ext_attr_length;
  495.   /*
  496.    * 'offset' is the offset of the first logical block of the file
  497.    * extent from the first logical (2048-byte-)sector.
  498.    */
  499.   if (blockshift)
  500.     offset = ((firstblock & ((1<<blockshift)-1))
  501.               << (11-blockshift));
  502.   else
  503.     offset = 0;
  504.   /*
  505.    * 'ext_loc' is the first logical sector of the file extent.
  506.    * 'loc' is the first logical sector to be read.
  507.    * 'last_loc' is the last logical sector of the file extent.
  508.    */
  509.   ext_loc = firstblock >> blockshift;
  510.   loc = ext_loc + ((p_file->pos + offset) >> 11);
  511.   last_loc = ext_loc + ((OBJ(p_file,dir)->data_length_m + offset - 1) >> 11);
  512.   todo = p_buffer_length;
  513.  
  514.   offset += p_file->pos;
  515.   offset &= 2047;
  516.   remain_block = 2048 - offset;
  517.  
  518.   while (todo) {
  519.     if (!Read_Contiguous_Sectors (cd, loc, last_loc)) {
  520.       return -1;
  521.     }
  522.  
  523.     remain_file = OBJ(p_file,dir)->data_length_m - p_file->pos;
  524.     /*
  525.      * 'todo' is the number of bytes in p_buffer which haven't been filled yet.
  526.      * 'remain' is remaining number of bytes in cd->buffer.
  527.      */
  528.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  529.     len = (todo < remain) ? todo : remain;
  530.     CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
  531.     buf_pos += len;
  532.     p_file->pos += len;
  533.     todo -= len;
  534.  
  535.     if (p_file->pos >= OBJ(p_file,dir)->data_length_m)
  536.       break;
  537.  
  538.     remain_block = 2048;
  539.     offset = 0;
  540.  
  541.     loc++;
  542.   }
  543.  
  544.   return buf_pos;
  545. }
  546.  
  547. t_ulong Extract_Date (directory_record *p_dir_record)
  548. {
  549.   struct ClockData ClockData;
  550.  
  551.   ClockData.sec   = p_dir_record->second;
  552.   ClockData.min      = p_dir_record->minute;
  553.   ClockData.hour  = p_dir_record->hour;
  554.   ClockData.mday  = p_dir_record->day;
  555.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  556.   ClockData.month = p_dir_record->month;
  557.   ClockData.year  = p_dir_record->year + 1900;
  558.  
  559.   if (CheckDate (&ClockData))
  560.     return Date2Amiga (&ClockData);
  561.   else
  562.     return 0;
  563. }
  564.  
  565. /* Return information on a "CDROM object."
  566.  */
  567.  
  568. LONG Iso_CDROM_Info (VOLUME *p_volume,CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  569. {
  570.   if (Iso_Is_Top_Level_Object (p_volume,p_obj)) {
  571.     p_info->name_length = 1;
  572.     p_info->name[0] = ':';
  573.     p_info->directory_f = TRUE;
  574.     p_info->file_length = 0;
  575.     p_info->date = Volume_Creation_Date (p_volume);
  576.   } else {
  577.     Convert_Iso_Name(p_volume,OBJ(p_obj,dir),p_info->name);
  578.     p_info->name_length = strlen(p_info->name);
  579.     p_info->directory_f = p_obj->directory_f;
  580.     p_info->symlink_f = p_obj->symlink_f;
  581.     p_info->file_length = OBJ(p_obj,dir)->data_length_m;
  582.     p_info->date = Extract_Date (OBJ(p_obj,dir));
  583.   }
  584.  
  585.   return 0;
  586. }
  587.  
  588. /* Browse all entries in a directory.
  589.  */
  590.  
  591. LONG Iso_Examine_Next (VOLUME *p_volume,CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  592.               unsigned long *p_offset)
  593. {
  594.   unsigned long offset;
  595.   unsigned char buffer[256];
  596.   directory_record *rec = (directory_record *)buffer;
  597.  
  598.  
  599.   if (!p_dir->directory_f || p_dir->symlink_f) {
  600.     return(ISOERR_BAD_ARGUMENTS);
  601.   }
  602.  
  603.   if (*p_offset == 0) {
  604.     /* skip first two directory entries: */
  605.  
  606.     if (!Get_Directory_Record (p_volume,rec,
  607.                         OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  608.                     0))
  609.       return(IoErr());
  610.  
  611.     offset = rec->length;
  612.  
  613.     if (!Get_Directory_Record (p_volume,rec,
  614.                       OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  615.                     offset))
  616.       return(IoErr());
  617.  
  618.     *p_offset = offset + rec->length;
  619.   }
  620.  
  621.   for (;;) {
  622.     if (OBJ(p_dir,dir)->data_length_m <= *p_offset)
  623.       return(ERROR_NO_MORE_ENTRIES);
  624.  
  625.     if (!Get_Directory_Record (p_volume,rec,
  626.                       OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  627.                     *p_offset))
  628.       return(IoErr());
  629.  
  630.     if (rec->length == 0)
  631.       /* go to next logical sector: */
  632.       *p_offset = (*p_offset & 0xfffff800) + 2048;
  633.     else
  634.       break;
  635.   }
  636.  
  637.   *p_offset += rec->length;
  638.  
  639.   Convert_Iso_Name(p_volume,rec,p_info->name);
  640.   p_info->name_length = strlen(p_info->name);
  641.   if (p_volume->protocol == PRO_ROCK &&
  642.             Is_A_Symbolic_Link (p_volume, rec)) {
  643.     p_info->symlink_f = 1;
  644.     p_info->directory_f = 0;
  645.   } else if (p_volume->protocol == PRO_ROCK &&
  646.              Has_System_Use_Field (p_volume, rec, "CL")) {
  647.     p_info->symlink_f = 0;
  648.     p_info->directory_f = 1;
  649.   } else {
  650.     p_info->symlink_f = 0;
  651.     p_info->directory_f = rec->flags & 2;
  652.   }
  653.   p_info->file_length = rec->data_length_m;
  654.   p_info->date = Extract_Date (rec);
  655.   p_info->suppl_info = rec;
  656.  
  657.   return(0);
  658. }
  659.  
  660. /* Clone a "CDROM object info."
  661.  */
  662.  
  663. void *Iso_Clone_Obj_Info (void *p_info)
  664. {
  665.   t_iso_obj_info *info = (t_iso_obj_info *) p_info;
  666.   t_iso_obj_info *new;
  667.  
  668.   new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  669.   if (!new)
  670.     return NULL;
  671.  
  672.   memcpy (new, info, sizeof (t_iso_obj_info));
  673.  
  674.   new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
  675.   if (!new->dir) {
  676.     FreeMem (new, sizeof (t_iso_obj_info));
  677.     return NULL;
  678.   }
  679.   memcpy (new->dir, info->dir, info->dir->length);
  680.  
  681.   return new;
  682. }
  683.  
  684. /* Find parent directory.
  685.  */
  686.  
  687. CDROM_OBJ *Iso_Find_Parent (VOLUME *p_volume,CDROM_OBJ *p_object)
  688. {
  689.   unsigned char buffer[256];
  690.   directory_record *dir = (directory_record *)buffer;
  691.   unsigned long dir_loc;
  692.   long pl;
  693.  
  694.  
  695.   if (p_object->directory_f)
  696.     dir_loc = OBJ(p_object,dir)->extent_loc_m + OBJ(p_object,dir)->ext_attr_length;
  697.   else
  698.     dir_loc = OBJ(p_object,parent_loc);
  699.  
  700.   if (!Get_Directory_Record (p_volume, dir, dir_loc, 0))
  701.     return NULL;
  702.  
  703.   if (p_object->directory_f) {
  704.     if (!Get_Directory_Record (p_volume, dir, dir_loc, dir->length))
  705.       return NULL;
  706.     if (p_volume->protocol == PRO_ROCK &&
  707.         (pl = RR_Parent_Link (p_volume, dir)) >= 0)
  708.       return Iso_Create_Directory_Obj (p_volume, pl);
  709.   }
  710.  
  711.   return Iso_Create_Directory_Obj (p_volume, dir->extent_loc_m);
  712. }
  713.  
  714. /* Test if p_object is the root directory.
  715.  */
  716.  
  717. t_bool Iso_Is_Top_Level_Object (VOLUME *p_volume,CDROM_OBJ *p_object)
  718. {
  719.   return p_object->directory_f &&
  720.          OBJ(p_object,dir)->extent_loc_m ==
  721.      VOL(p_volume,pvd).root.extent_loc_m;
  722. }
  723.  
  724. /* Test if two objects are equal.
  725.  */
  726.  
  727. t_bool Iso_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
  728. {
  729.   return (OBJ(p_obj1,dir)->extent_loc_m ==
  730.       OBJ(p_obj2,dir)->extent_loc_m);
  731. }
  732.  
  733. /*
  734.  * Convert p_num digits into an integer value:
  735.  */
  736.  
  737. int Digs_To_Int (char *p_digits, int p_num)
  738. {
  739.   int result = 0;
  740.   int i;
  741.  
  742.   for (i=0; i<p_num; i++)
  743.     result = result * 10 + p_digits[i] - '0';
  744.  
  745.   return result;
  746. }
  747.  
  748. /*
  749.  * Return volume creation date as number of seconds since 1-Jan-1978:
  750.  */
  751.  
  752. t_ulong Iso_Creation_Date (VOLUME *p_volume)
  753. {
  754.   struct ClockData ClockData;
  755.   char *dt = VOL(p_volume,pvd).vol_creation;
  756.  
  757.   ClockData.sec   = Digs_To_Int (dt+12, 2);
  758.   ClockData.min      = Digs_To_Int (dt+10, 2);
  759.   ClockData.hour  = Digs_To_Int (dt+8, 2);
  760.   ClockData.mday  = Digs_To_Int (dt+6, 2);
  761.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  762.   ClockData.month = Digs_To_Int (dt+4, 2);
  763.   ClockData.year  = Digs_To_Int (dt, 4);
  764.  
  765.   if (CheckDate (&ClockData))
  766.     return Date2Amiga (&ClockData);
  767.   else
  768.     return 0;
  769. }
  770.  
  771. t_ulong Iso_Volume_Size (VOLUME *p_volume)
  772. {
  773.   return VOL(p_volume,pvd).space_size_m;
  774. }
  775.  
  776. t_ulong Iso_Volume_Free (VOLUME *p_volume)
  777. {
  778.   return 0;
  779. }
  780.  
  781. t_ulong Iso_Block_Size (VOLUME *p_volume)
  782. {
  783.   return VOL(p_volume,pvd).block_size_m;
  784. }
  785.  
  786. void Iso_Volume_ID (VOLUME *p_volume, char *p_buffer, int p_buf_length)
  787. {
  788.   char *iso_name = VOL(p_volume,pvd).volume_id;
  789.   int iso_len;
  790.   int len;
  791.  
  792.   for (iso_len = 30; iso_len; iso_len--) {
  793.     if (iso_name[iso_len-1] != ' ')
  794.       break;
  795.   }
  796.  
  797.   len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
  798.   if (len > 0)
  799.   {
  800.     memcpy (p_buffer, iso_name, len);
  801.   }
  802.   p_buffer[len] = 0;
  803. }
  804.  
  805. t_ulong Iso_Location (VOLUME *p_volume,CDROM_OBJ *p_object)
  806. {
  807.   return OBJ(p_object,dir)->extent_loc_m;
  808. }
  809.  
  810. t_ulong Iso_File_Length (CDROM_OBJ *p_obj)
  811. {
  812.   return OBJ(p_obj,dir)->data_length_m;
  813. }
  814.  
  815. t_handler g_iso_handler = {
  816.   Iso_Close_Vol_Info,
  817.   Iso_Open_Top_Level_Directory,
  818.   Iso_Open_Obj_In_Directory,
  819.   Iso_Find_Parent,
  820.   Iso_Close_Obj,
  821.   Iso_Read_From_File,
  822.   Iso_CDROM_Info,
  823.   Iso_Examine_Next,
  824.   Iso_Clone_Obj_Info,
  825.   Iso_Is_Top_Level_Object,
  826.   Iso_Same_Objects,
  827.   Iso_Creation_Date,
  828.   Iso_Volume_Size,
  829.   Iso_Volume_Free,
  830.   Iso_Volume_ID,
  831.   Iso_Location,
  832.   Iso_File_Length,
  833.   Iso_Block_Size
  834. };
  835.  
  836.